package com.example.filters;

import com.alibaba.fastjson.JSON;
import com.example.common.constants.AuthContants;
import com.example.common.entitys.AuthUserDetails;
import com.example.threadloacls.AuthUserDetailsThreadlocal;
import com.example.utils.ResponseUtils;
import com.example.utils.RestResponse;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class ShiroInterceptor implements HandlerInterceptor {

    private static final Logger logger = LoggerFactory.getLogger(ShiroInterceptor.class);

    private static   List<String> excludedAuthPages = null;



    public ShiroInterceptor(){
        excludedAuthPages = new ArrayList<>();
        excludedAuthPages.add("/noneedlogin");
        excludedAuthPages.add("/common/");
    }


    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if (handler instanceof HandlerMethod == false) {
            return true;//无需校验
        }
        boolean isExcelude = false;
        boolean isLogin = false;
        AuthUserDetails detail =  AuthUserDetailsThreadlocal.getUserSession();
        if(detail != null){
            isLogin = true;
        }
        String url = request.getRequestURI();
        for( String exclude :excludedAuthPages ){
            if (url.startsWith(exclude)){
                isExcelude = true;
                break;
            }
        }
        if(isExcelude){
            logger.info("在白名单中，不进行拦截。url="+url);
            return true;
        }else{
            String  currentuser = MDC.get("currentuser");
            String  token = MDC.get("token");
            String httpMethod = request.getMethod();
            if(isLogin){
                Method method = ((HandlerMethod) handler).getMethod();
                boolean isAnnotationPresentRequiresPermissions = method.isAnnotationPresent(RequiresPermissions.class);
                if(!isAnnotationPresentRequiresPermissions){
                    //没有使用注解RequiresPermissions，则不需要进行资源权限验证
                    logger.info("没有设置需要属于需要拦截的资源，不进行拦截。url="+url+",httpMethod="+httpMethod);
                    return true;
                }else{
                    RequiresPermissions annotation = method.getAnnotation(RequiresPermissions.class);
                    String[] values = annotation.value();
                    AuthUserDetails userDetails = AuthUserDetailsThreadlocal.getUserSession();
                    Map<String,String> permsMap = userDetails.getPermsMap();
                    List<String> noExistPermissios = new ArrayList<>(values.length);
                    for(String value:values){
                        if(!permsMap.containsKey(value)){
                            noExistPermissios.add(value);
                        }
                    }
                    if(noExistPermissios.size() >= 1){
                        logger.info("未登录访问资源，url="+url+",currentuser="+currentuser+",token="+token+",您还需要权限："+ JSON.toJSONString(noExistPermissios));
                        RestResponse ajaxResponse = RestResponse.build(AuthContants.NO_ENOUGH_AUTHORIZED_FAILURE_CODE,"权限不足，请联系管理员进行授权访问。您还需要权限："+JSON.toJSONString(noExistPermissios));
                        ResponseUtils.outJson(response,ajaxResponse);
                        return false;
                    }else{
                        return true;
                    }
                }
            }else{
                logger.info("未登录访问资源，url="+url+",currentuser="+currentuser+",token="+token);
                RestResponse ajaxResponse = RestResponse.build(AuthContants.COMMON_AUTHORIZED_FAILURE_CODE,"登录后才能访问资源");
                ResponseUtils.outJson(response,ajaxResponse);
                return false;
            }
        }




    }



}
